import os
import openai
import platform


class OpenAIClient:
    def __init__(self, model_name="glm-4-flash", api_key="null",
                 top_p=0.8, temperature=0.9, max_tokens=1024, model_path=None):
        self.model_name = model_name
        self.model_path = model_path
        self.api_key = api_key
        self.top_p = top_p
        self.temperature = temperature
        self.max_tokens = max_tokens

    # 定义一个方法用于检查 OpenAI 的 API 密钥是否为空
    def check_api_key(self):
        if not self.api_key:
            # 如果 API 密钥为空时候从环境变量获取
            self.api_key = os.getenv("OPENAI_API_KEY")
            # 如果环境变量中也没有获取到
            if not self.api_key:
                raise ValueError("请在 config.yaml 设置的 API 密钥，或者请在环境变量中设置 OPENAI_API_KEY=your_api_key！")
        return self.api_key

    # 定义一个方法用于设置 Prompt
    def set_prompt(self):
        # 功能是首先获取本机是 Windows 还是 Linux，MacOS，然后根据不同的操作系统设置不同的 Prompt。
        system = platform.system().lower()
        # print(system)
        if system == "linux":
            try:
                distro = platform.freedesktop_os_release().get("NAME", "Linux")
            except AttributeError:
                distro = platform.linux_distribution()[0] or "Linux"
            system_info = {"type": "Linux", "details": distro}
        elif system == "windows":
            system_info = {"type": "Windows", "details": "PowerShell"}
        elif system == "darwin":
            system_info = {"type": "Mac OS", "details": "Mac OS X"}
        else:
            system_info = {"type": "Unknown", "details": "Unknown"}
        # 根据系统类型设置提示模板
        # 从命令行终端角度优化后的 system_prompt，更加注重命令行操作的细节和用户体验
        system_prompt = (
            f"你是一个 {system_info['type']} 命令行终端，你的主要任务是处理用户输入的各种任务。你具备强大的能力，能够将用户输入的自然语言描述准确无误地转换为 {system_info['type']} 命令，"
            f"以便用户更便捷地操作 {system_info['details']} 系统。此外，你还可以和用户进行日常的交流。"
            "在处理用户请求时，你必须将你的回复以 JSON 对象的形式呈现，这个 JSON 对象需要包含以下几个重要的字段，不能回复json格式以外的内容："
            "- `description`：该字段用于对用户输入的自然语言描述进行详细解释。在解释时，你应该清晰地阐述将如何处理用户的请求，"
            "具体说明将采取的操作、操作的目标和预期的效果。使用清晰、简洁的语言，避免使用模糊的表述，如'用户在询问'或'想要'等。"
            "若解释内容需要多行展示，可以使用 '\\n' 进行换行，以确保信息的完整性和可读性。"
            f"- `code`：此部分存储根据用户的自然语言描述生成的相应 {system_info['type']} 命令。"
            f"生成的命令必须严格遵循 {system_info['type']} 的语法规则，确保在当前系统环境下能够正确执行。"
            "在创建命令时，需要充分考虑系统的环境设置、用户权限以及其他可能影响命令执行的因素，避免生成无法执行的命令。"
            "- `is_code`：这是一个布尔型字段，用于指示是否需要执行生成的命令。你需要根据用户的意图来决定其取值。"
            "如果用户期望执行该命令，此值应设为 True；若用户只是在寻求信息，不要求执行命令，此值应为 False。"
            "- `Native`：此布尔型字段用于区分用户的请求是否涉及系统本机信息的查询。"
            "当用户的请求与系统本机信息相关，如查询系统硬件信息（如 CPU 信息、内存信息等）、系统软件信息（如已安装软件列表、软件版本等）、系统配置信息（如系统参数、环境变量等），将该值设置为 True；"
            "若用户的请求是关于外部资源（如网络资源、远程服务器资源等）的操作，或者不涉及本机信息的查询，则将此值设置为 False。"
            "以下是一个示例："
            "假设用户输入 '列出当前目录下的所有文件'，你必须给出的 JSON 响应如下："
            "```json"
            "{"
            "'description':'如下是当前目录的所有文件，展示文件名称、类型和大小等信息。',"
            "'code':'ls -l',"
            "'is_code':true,"
            "'Native':false"
            "}"
            "```"
            "注意事项有：打开python,mysql,redis,java,node,shell等命令行工具时创新打开新的窗口，不要在当前窗口打开。"
            "日常交流的时候你是一个非常友善的助手，你会用非常友善的语气和用户交流。并且遵守json格式返回。"
        )
        return system_prompt

    def chat(self, massage):
        """
        聊天方法
        :param massage:  返回字典格式[{"role":"user", "content":"hello"}], user表示用户输入，assistant表示助手回答
        :return:
        """
        # 调用 set_prompt 方法设置 Prompt
        system_prompt = self.set_prompt()
        messages_history = [{"role": "system", "content": system_prompt}]
        # 将用户输入的 massage 添加到 messages 中
        messages_history.extend(massage)
        # 调用 check_api_key 方法检查 API 密钥是否为空
        self.check_api_key()

        # 判断self.model_path是否为空，不为空则使用本地模型
        if self.model_path:
            client = openai.OpenAI(api_key=self.api_key, base_url=self.model_path)
        else:
            client = openai.OpenAI(api_key=self.api_key)

        try:
            # 使用 OpenAI 的 ChatCompletion 接口进行聊天
            response = client.chat.completions.create(
                model=self.model_name,
                messages=messages_history,
                top_p=self.top_p,
                temperature=self.temperature,
                max_tokens=self.max_tokens
            )
            # 返回 ChatGPT 的回答
            return response.choices[0].message.content
        except openai.AuthenticationError:
            print("认证错误：请检查 API 密钥是否正确。")
        except openai.RateLimitError:
            print("速率限制错误：你可能超过了 API 的速率限制，请稍后再试。")
        except openai.APIConnectionError:
            print("API 连接错误：请检查网络连接或 OpenAI 服务是否可用。")
        except openai.Timeout:
            print("超时错误：请求超时，请检查网络连接或调整超时设置。")
        except Exception as e:
            print(f"其他错误：{e}")
        return None
